﻿/************************************
*研华板卡
*轴类
*
*************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Advantech.Motion;
using System.Windows.Forms;
using System.Threading;

namespace AdvantechMontion
{
    public class AxisOperator
    {
        /// <summary>
        /// 卡号
        /// </summary>
        public int CardNum = 0;
        /// <summary>
        /// 轴号
        /// </summary>
        public int AxisNum = 0;
        /// <summary>
        /// 脉冲换算
        /// </summary>
        public double m_pdfScale;
        /// <summary>
        /// 轴初始化完成
        /// </summary>
        public bool m_IniSts = false;
        public IntPtr m_Axishand = new IntPtr();
        /// <summary>
        /// 轴回零完成
        /// </summary>
        public bool IsHome { internal set; get; }
        /// <summary>
        /// 轴名称
        /// </summary>
        public string AxisName = "";
        /// <summary>
        /// 单轴使能打开
        /// </summary>
        public void ServoOn()
        {
            UInt32 Result;
            string strTemp;

            if (m_IniSts != true)
            {
                return;
            }

            Result = Motion.mAcm_AxResetError(m_Axishand);
            Result = Motion.mAcm_AxSetSvOn(m_Axishand, 1);

            if (Result != (uint)ErrorCode.SUCCESS)
            {
                strTemp = string.Format("第{0}张卡第{1}个轴无法使能--------------", CardNum, AxisNum);

                strTemp = strTemp + "Servo On Failed With Error Code: [0x" + Convert.ToString(Result, 16) + "]";

                ShowMessages(strTemp, Result);
                return;
            }

        }
        /// <summary>
        /// 单轴使能关闭
        /// </summary>
        public void ServoOff()
        {
            UInt32 Result;
            string strTemp;

            if (m_IniSts != true)
            {
                return;
            }
           
            Result = Motion.mAcm_AxSetSvOn(m_Axishand, 0);

            if (Result != (uint)ErrorCode.SUCCESS)
            {
                strTemp = string.Format("第{0}张卡第{1}个轴无法关闭使能--------------", CardNum, AxisNum);

                strTemp = strTemp + "Servo Off Failed With Error Code: [0x" + Convert.ToString(Result, 16) + "]";
                ShowMessages(strTemp, Result);
                return;
            }

        }
        /// <summary>
        /// 报警复位
        /// </summary>
        public void ResetError()
        {
            UInt32 Result;
            string strTemp;

            if (m_IniSts != true)
            {
                return;
            }

            Result = Motion.mAcm_AxResetError(m_Axishand);
        }
        /// <summary>
        /// 
        /// </summary>
        public void ClearPos()
        {
            double cmdPosition = 0;
            Motion.mAcm_AxSetCmdPosition(m_Axishand, cmdPosition);
            Motion.mAcm_AxSetActualPosition(m_Axishand, cmdPosition);
        }

        public void Move_PTP_Rel(double AxVelLow, double AxVelHigh, double AxAcc, double AxDec, double Pos)
        {
            UInt32 Result;
            string strTemp;

            if (m_IniSts != true)
            {
                return;
            }

            Result = Motion.mAcm_SetF64Property(m_Axishand, (uint)PropertyID.PAR_AxVelLow, AxVelLow);
            Result = Motion.mAcm_SetF64Property(m_Axishand, (uint)PropertyID.PAR_AxVelHigh, AxVelHigh);
            Result = Motion.mAcm_SetF64Property(m_Axishand, (uint)PropertyID.PAR_AxAcc, AxAcc);
            Result = Motion.mAcm_SetF64Property(m_Axishand, (uint)PropertyID.PAR_AxDec, AxDec);
 
            Result = Motion.mAcm_AxMoveRel(m_Axishand, Pos);

            if (Result != (uint)ErrorCode.SUCCESS)
            {
                strTemp = "PTP Move Failed With Error Code: [0x" + Convert.ToString(Result, 16) + "]";
                ShowMessages(strTemp, Result);
            }

            //WaitStop();

        }

        private static object MoveAxisLock = new object();

        public void Move_PTP_Abs(double AxVelLow, double AxVelHigh, double AxAcc, double AxDec, double Pos, bool bWait = true)
        {
            UInt32 Result;
            string strTemp;

            if (m_IniSts != true)
            {
                return;
            }
        line:
            ResetError();
            Result = Motion.mAcm_SetF64Property(m_Axishand, (uint)PropertyID.PAR_AxVelLow, AxVelLow);
            Result = Motion.mAcm_SetF64Property(m_Axishand, (uint)PropertyID.PAR_AxVelHigh, AxVelHigh);
            Result = Motion.mAcm_SetF64Property(m_Axishand, (uint)PropertyID.PAR_AxAcc, AxAcc);
            Result = Motion.mAcm_SetF64Property(m_Axishand, (uint)PropertyID.PAR_AxDec, AxDec);

            Result = Motion.mAcm_AxMoveAbs(m_Axishand, Pos);

            if (Result != (uint)ErrorCode.SUCCESS)
            {
                strTemp = AxisNum+"PTP Move Failed With Error Code: [0x" + Convert.ToString(Result, 16) + "]";
                ShowMessages(strTemp, Result);
                goto line;
            }

            if (bWait)
            {
                WaitStop();
            }

        }
        /// <summary>
        /// Jog点动
        /// </summary>
        /// <param name="AxVelLow"></param>
        /// <param name="AxVelHigh"></param>
        /// <param name="AxAcc"></param>
        /// <param name="dir"></param>
        public void Move_Jog_MoveVel(double AxVelLow, double AxVelHigh, double AxAcc, int dir)
        {
            UInt32 Result;
            string strTemp;

            if (m_IniSts != true)
            {
                return;
            }

            Result = Motion.mAcm_SetF64Property(m_Axishand, (uint)PropertyID.PAR_AxVelLow, AxVelLow);
            Result = Motion.mAcm_SetF64Property(m_Axishand, (uint)PropertyID.PAR_AxVelHigh, AxVelHigh);
            Result = Motion.mAcm_SetF64Property(m_Axishand, (uint)PropertyID.PAR_AxAcc, AxAcc);
            Result = Motion.mAcm_SetF64Property(m_Axishand, (uint)PropertyID.PAR_AxDec, AxAcc);

            //按下按钮时，启动MoveVel持续运动，1为负向运动，0为正向运动,该运动会持续运动下去，从低速度开始运动，以加速度值加速到高速。
            Result = Motion.mAcm_AxMoveVel(m_Axishand, Convert.ToUInt16(dir));

        }

        /// <summary>
        /// 单轴回零      单位：mm/ms
        /// </summary>
        /// <param name="AxVelLow"></param>
        /// <param name="AxVelHigh"></param>
        /// <param name="AxAcc"></param>
        /// <param name="AxDec"></param>
        /// <param name="Mode">模式</param>
        /// <param name="Dir">方向（0为正方向，1负方向）</param>
        public void HomeByAxHome(double AxVelLow, double AxVelHigh, double AxAcc, double AxDec, uint Mode, uint Dir,double CrossDistance)
        {
            IsHome = false;
            UInt32 Result;
            string strTemp;
            IsHome = false;
            if (m_IniSts != true)
            {
       
                return;
            }

            Result = Motion.mAcm_AxResetError(m_Axishand);
            bool arm = false, lmtp = false, lmtn = false, svon = false;
            this.GetAxisStatus(ref arm, ref lmtp, ref lmtn, ref svon);
            if (arm == true || svon == false)
            {
                
                return;
            }
  
            Result = Motion.mAcm_SetF64Property(m_Axishand, (uint)PropertyID.PAR_AxHomeCrossDistance, CrossDistance);
            Result = Motion.mAcm_SetF64Property(m_Axishand, (uint)PropertyID.PAR_AxHomeVelLow, AxVelLow);
            Result = Motion.mAcm_SetF64Property(m_Axishand, (uint)PropertyID.PAR_AxHomeVelHigh, AxVelHigh);
            Result = Motion.mAcm_SetF64Property(m_Axishand, (uint)PropertyID.PAR_AxHomeAcc, AxAcc);
            Result = Motion.mAcm_SetF64Property(m_Axishand, (uint)PropertyID.PAR_AxHomeDec, AxDec);
            //选择Mode7模式，代码需要写6,最后一个参数为方向，0为正方向，1负方向。
            Result = Motion.mAcm_AxMoveHome(m_Axishand, Mode, Dir);

            if (Result != (uint)ErrorCode.SUCCESS)
            {
                IsHome = false;
                strTemp = string.Format("第{0}张卡第{1}个轴回零失败--------------", CardNum, AxisNum);
                strTemp = strTemp + "Go Home Failed With Error Code: [0x" + Convert.ToString(Result, 16) + "]";
                ShowMessages(strTemp, Result);
                return;
            }
            UInt16 AxState = new UInt16();
            do
            {
                //读取当前轴的运行状态
                Motion.mAcm_AxGetState(m_Axishand, ref AxState);
                if (AxState == (uint)AxisState.STA_AX_ERROR_STOP)
                {
                    IsHome = false;
                    strTemp = string.Format("第{0}张卡第{1}个轴回零失败--------------", CardNum, AxisNum);
                    strTemp = strTemp + "Go Home Failed With Error Code: [0x" + Convert.ToString(AxState, 16) + "]";
                    ShowMessages(strTemp, AxState);
                    return;
                }
            }while (AxState != (uint)AxisState.STA_AX_READY);
            Thread.Sleep(1500);
            ClearPos();
            IsHome = true;
        }

        public void HomeByMoveHome(double AxVelLow, double AxVelHigh, double AxAcc, double AxDec, uint Mode, uint Dir, double CrossDistance)
        {
            UInt32 Result;
            string strTemp;
            IsHome = false;
            if (m_IniSts != true)
            {
     
                return;
            }

            Result = Motion.mAcm_AxResetError(m_Axishand);
            Result = Motion.mAcm_SetF64Property(m_Axishand, (uint)PropertyID.PAR_AxHomeCrossDistance, CrossDistance);
            Result = Motion.mAcm_SetF64Property(m_Axishand, (uint)PropertyID.PAR_AxHomeVelLow, AxVelLow);
            Result = Motion.mAcm_SetF64Property(m_Axishand, (uint)PropertyID.PAR_AxHomeVelHigh, AxVelHigh);
            Result = Motion.mAcm_SetF64Property(m_Axishand, (uint)PropertyID.PAR_AxHomeAcc, AxAcc);
            Result = Motion.mAcm_SetF64Property(m_Axishand, (uint)PropertyID.PAR_AxHomeDec, AxDec);
            //Result = Motion.mAcm_SetF64Property(m_Axishand, (uint)PropertyID.PAR_AxVelLow, AxVelLow * m_pdfScale);
            //Result = Motion.mAcm_SetF64Property(m_Axishand, (uint)PropertyID.PAR_AxVelHigh, AxVelHigh * m_pdfScale);
            //Result = Motion.mAcm_SetF64Property(m_Axishand, (uint)PropertyID.PAR_AxAcc, AxAcc * m_pdfScale);
            //Result = Motion.mAcm_SetF64Property(m_Axishand, (uint)PropertyID.PAR_AxDec, AxDec * m_pdfScale);
            Result = Motion.mAcm_AxHome(m_Axishand, Mode, Dir);

            if (Result != (uint)ErrorCode.SUCCESS)
            {
                IsHome = false;

                strTemp = string.Format("第{0}张卡第{1}个轴回零失败--------------", CardNum, AxisNum);

                strTemp = strTemp + "Go Home Failed With Error Code: [0x" + Convert.ToString(Result, 16) + "]";

                ShowMessages(strTemp, Result);
                return;
            }
            Thread.Sleep(1500);
            ClearPos();
            IsHome = true;

        }
        /// <summary>
        /// 
        /// </summary>
        public void Stop_Axis()
        {
            uint Result;
            string strTemp;

            if (m_IniSts)
            {
                //To command axis to decelerate to stop.
                Result = Motion.mAcm_AxStopDec(m_Axishand);
                if (Result != (uint)ErrorCode.SUCCESS)
                {
                    strTemp = "Axis To decelerate Stop Failed With Error Code: [0x" + Convert.ToString(Result, 16) + "]";
                    ShowMessages(strTemp, Result);
                    return;
                }
            }
            return;
        }
        /// <summary>
        /// 等待轴运动停止
        /// </summary>
        public void WaitStop()
        {
            UInt16 AxState = new UInt16();

            do
            {
                //读取当前轴的运行状态
                Motion.mAcm_AxGetState(m_Axishand, ref AxState);

                if (AxState == (uint)AxisState.STA_AX_ERROR_STOP)
                {
                    IsHome = false;
                    string strTemp = string.Format("第{0}张卡第{1}个轴报警--------------", CardNum, AxisNum);
                    MessageBox.Show(strTemp, "错误信息", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    break;
                }

            } while (AxState != (uint)AxisState.STA_AX_READY);
        }


        /// <summary>
        /// 读取轴上带的输入IO
        /// </summary>
        /// <param name="DiNumber">位数</param>
        /// <returns>true-有信号，false-无信号</returns>
        public bool GetAxisDI(ushort DiNumber)
        {
            UInt32 Result;
            byte BitIn = 0;

            if (m_IniSts != true)
            {
                return false;
            }

            //读取脉冲卡板卡上轴带的Di信号, DiNumber从0到3，bitIn为1时代表打开，为0时代表关闭。
            Result = Motion.mAcm_AxDiGetBit(m_Axishand, DiNumber, ref BitIn);

            if (BitIn == 1)
                return true;
            else if (BitIn == 0)
                return false;
            else
                return false;

        }
        /// <summary>
        /// 读取轴上带的输出IO
        /// </summary>
        /// <param name="DiNumber"></param>
        /// <returns></returns>
        public bool GetAxisDO(ushort DiNumber)
        {
            UInt32 Result;
            byte bitDo = 0;

            if (m_IniSts != true)
            {
                return false;
            }

            //读取脉冲卡板卡轴上带的Do信号时，DoChannel从4到7，DoValue为1时代表打开，为0时代表关闭
            Result = Motion.mAcm_AxDoGetBit(m_Axishand, DiNumber, ref bitDo);

            if (bitDo == 1)
                return true;
            else if (bitDo == 0)
                return false;
            else
                return false;

        }
        /// <summary>
        /// 写入轴上自带的输出IO
        /// </summary>
        /// <param name="DiNumber"></param>
        /// <param name="DoValue"></param>
        /// <returns></returns>
        public bool SetAxisDO(ushort DiNumber, byte DoValue)
        {
            UInt32 Result;
            string strTemp;

            //写入脉冲卡板卡轴上带的Do信号时，DoChannel从4到7，DoValue为1时代表打开，为0时代表关闭
            Result = Motion.mAcm_AxDoSetBit(m_Axishand, DiNumber, DoValue);

            if (Result != (uint)ErrorCode.SUCCESS)
            {
                strTemp = "输出信号失败 With Error Code: [0x" + Convert.ToString(Result, 16) + "]";

                ShowMessages(strTemp, Result);
                return false;
            }

            return true;
        }
        /// <summary>
        /// 读取当前轴的运行状态
        /// </summary>
        /// <returns></returns>
        public AxisState GetAxisRunStatus()
        {
            UInt16 AxState = new UInt16();
            //读取当前轴的运行状态
            Motion.mAcm_AxGetState(m_Axishand, ref AxState);

            return (AxisState)AxState;
        }
        /// <summary>
        /// 获得轴的状态
        /// </summary>
        /// <param name="arm"></param>
        /// <param name="lmtp"></param>
        /// <param name="lmtn"></param>
        /// <param name="svon"></param>
        public void GetAxisStatus(ref bool arm, ref bool lmtp, ref bool lmtn, ref bool svon)
        {
            UInt32 Result;
            UInt32 IOStatus = new UInt32();

            if (m_IniSts != true)
            {
                IsHome = false;
                return;
            }

            //获得轴的状态灯标志位
            Result = Motion.mAcm_AxGetMotionIO(m_Axishand, ref IOStatus);
            if (Result == (uint)ErrorCode.SUCCESS)
            {
                if ((IOStatus & (uint)Ax_Motion_IO.AX_MOTION_IO_ALM) > 0)//伺服报警
                {
                    //代表该信号触发了
                    arm = true;
                }
                else
                {
                    //代表该信号未触发
                    arm = false;
                }

                if ((IOStatus & (uint)Ax_Motion_IO.AX_MOTION_IO_LMTP) > 0)//正极限
                {
                    lmtp = true;
                }
                else
                {
                    lmtp = false;
                }

                if ((IOStatus & (uint)Ax_Motion_IO.AX_MOTION_IO_LMTN) > 0)//负极限
                {
                    lmtn = true;
                }
                else
                {
                    lmtn = false;
                }

                if ((IOStatus & (uint)Ax_Motion_IO.AX_MOTION_IO_SVON) > 0)//伺服使能
                {
                    svon = true;
                }
                else
                {
                    svon = false;
                }

            }
        }


        public void GetAxisORG(ref bool org)
        {
            UInt32 Result;
            UInt32 IOStatus = new UInt32();

            if (m_IniSts != true)
            {
                IsHome = false;
                return;
            }

            //获得轴的状态灯标志位
            Result = Motion.mAcm_AxGetMotionIO(m_Axishand, ref IOStatus);
            if (Result == (uint)ErrorCode.SUCCESS)
            {
                if ((IOStatus & (uint)Ax_Motion_IO.AX_MOTION_IO_ORG) > 0)
                {
                    //代表该信号触发了
                    org = true;
                }
                else
                {
                    //代表该信号未触发
                    org = false;
                }

            }
        }


        private void ShowMessages(string DetailMessage, uint errorCode)
        {
            StringBuilder ErrorMsg = new StringBuilder("", 100);
            //Get the error message according to error code returned from API
            Boolean res = Motion.mAcm_GetErrorMessage(errorCode, ErrorMsg, 100);
            string ErrorMessage = "";
            if (res)
                ErrorMessage = ErrorMsg.ToString();
            MessageBox.Show(DetailMessage + "\r\nError Message:" + ErrorMessage, "错误信息", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

    }
}
